<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style>
        body {
            display: flex;
        }

        .container,
        .preview {
            display: block;
            position: relative;
            box-sizing: border-box;
            height: 240px;
            width: 400px;
            margin-left: 20px;
        }

        input {
            position: absolute;
            inset: 0;
            opacity: 0;
        }

        img {
            width: 100%;
            object-fit: cover;
        }

        .select-file {
            position: absolute;
            height: 100%;
            width: 100%;
            border: 6px dashed #666;
            cursor: pointer;
            --w: 6px;
            --h: 60px;
        }

        .select-file::before,
        .select-file::after {
            content: "";
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            width: var(--w);
            height: var(--h);
            background-color: #666;
        }

        .select-file::after {
            transform: translate(calc(var(--w) / -2), calc(var(--h) / -2)) rotate(90deg);
        }

        .compress-bef,
        .compress-aft {
            position: absolute;
            bottom: -70px;
            left: 6%;
        }
    </style>
</head>

<body>
    <label class="container">
        <div class="select-file"></div>
        <input type="file" id="compress" />
        <p class="compress-bef">
            压缩前`base64`长度：
            <span></span>
        </p>
    </label>

    <div class="preview">
        <p class="compress-aft">
            压缩后`base64`长度：
            <span></span>
        </p>
    </div>

    <script>
        const container = document.querySelector('.container'),
            inp = container.querySelector('input'),
            seleFile = container.querySelector('.select-file'),
            preview = document.querySelector('.preview'),
            befSize = document.querySelector('.compress-bef span'),
            aftSize = preview.querySelector('.compress-aft span');

        inp.onchange = async ({ target: { files: [file] } }) => {
            const size = file.size / 1024;
            
            const [img, base64] = await createImg(file);
            container.appendChild(img);
            console.log('bef', base64)
            befSize.textContent = base64.length;
            setImgWrap();

            const compressBase64 = createCompressImg(file);
            console.log('aft', compressBase64)
            const compressImg = await createImg(compressBase64);
            preview.appendChild(compressImg[0]);
            aftSize.textContent = compressBase64.length;

            const h1 = document.createElement('h1');
            h1.style.flexGrow = 0;
            h1.textContent = '压缩率：' + ((1 - compressBase64.length / base64.length) * 100).toFixed(2) + '%' ;
            document.body.appendChild(h1)
        };

        function createCompressImg(file, quality) {
            const cvs = document.createElement('canvas'),
                ctx = cvs.getContext('2d'),
                img = container.querySelector('img');
            cvs.width = img.width;
            cvs.height = img.height;

            ctx.drawImage(img, 0, 0, img.width, img.height);
            return cvs.toDataURL('image/jpeg', quality);
        }

        function createImg(blob) {
            const img = new Image();

            if (typeof blob !== 'string') {
                const fr = new FileReader();
                fr.onload = function () {
                    img.src = this.result;
                    blob = this.result;
                };
                fr.readAsDataURL(blob);
            }
            else {
                img.src = blob;
            }

            return new Promise((resolve) => {
                img.onload = () => {
                    resolve([img, blob]);
                };
            });
        }

        function setImgWrap() {
            const flag = getComputedStyle(seleFile).display === 'block'
                ? 'none'
                : 'block';

            seleFile.style.display = flag;
        }
    </script>
</body>

</html>